package com.joker.search.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.joker.common.core.utils.StringUtils;
import com.joker.search.common.domain.SkuEsModel;
import com.joker.search.server.service.ProductService;
import com.joker.search.server.vo.SearchParam;
import com.joker.search.server.vo.SearchResult;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
public class ProductServiceImpl implements ProductService {


    @Autowired
    private RestHighLevelClient client;


    @Override
    public boolean productStatsUp(List<SkuEsModel> skuEsModelList) {


        BulkRequest bulkRequest = new BulkRequest();
        skuEsModelList.stream().forEach(skuEsModel -> {


            IndexRequest indexRequest = new IndexRequest();
            indexRequest.index("product");
            indexRequest.id(skuEsModel.getSkuId().toString());
            indexRequest.source(JSON.toJSONString(skuEsModel), XContentType.JSON);
            bulkRequest.add(indexRequest);


        });
        BulkResponse bulk = null;
        try {
            bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        boolean b = bulk.hasFailures();
        return b;

    }

    @Override
    public SearchResult search(SearchParam searchParam) throws IOException {

        //1. 构建searchRequest
        SearchRequest searchRequest = buildSearchRequest(searchParam);
        //2. 执行search
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //3. 解析response
        SearchResult searchResult = analyerResponse(searchResponse,searchParam);
        return searchResult;
    }



    private SearchResult analyerResponse(SearchResponse searchResponse,SearchParam searchParam) {
        SearchResult searchResult =  new SearchResult();

        /**
         * ======================================
         *
         hits
         */
        SearchHits hits = searchResponse.getHits();
        if (hits == null || hits.getHits().length == 0) {
            // 如果没有数据，检查日志或直接返回
            System.out.println("No hits found in search response");
            return searchResult; // 或者设置为返回一个空的 SearchResult
        }

        /** * 查询到的所有商品信息*/
//        private List<SkuEsModel> products;
        List skuEsModelList = new ArrayList();
        for (SearchHit hit : hits.getHits()) {

            String skuEsModelString = hit.getSourceAsString();
            try {
                SkuEsModel skuEsModel = JSON.parseObject(skuEsModelString, SkuEsModel.class);
                if (skuEsModel == null) {
                    System.out.println("Failed to parse skuEsModel for hit: " + skuEsModelString);
                }
                // 处理高亮
                if(StringUtils.isNotBlank(searchParam.getKeyword())){
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    HighlightField skuTitleHighlightField = highlightFields.get("skuTitle");
                    if (skuTitleHighlightField.getFragments().length > 0) {
                        skuEsModel.setSkuTitle(skuTitleHighlightField.getFragments()[0].toString());
                    }
                }
                skuEsModelList.add(skuEsModel);
            }catch (Exception e){
                System.out.println("Error parsing skuEsModel: " + skuEsModelString);
                e.printStackTrace();
            }
        }

        searchResult.setProducts(skuEsModelList);
        /*** 当前页码*/
//        private Integer pageNum;
        searchResult.setPageNum(searchParam.getPageNum());
        /** 总记录数*/
//        private Long total;
        searchResult.setTotal(hits.getTotalHits().value);
        /** * 总页码*/
//        private Integer totalPages;
        searchResult.setTotalPages(
                Long.valueOf(searchResult.getTotal()%20==0?searchResult.getTotal()/20:(searchResult.getTotal()/20+1)).intValue()
        );

        /**
         * ======================================
         *
         * 以下是agg聚合结果解析
         */
        Aggregations aggregations = searchResponse.getAggregations();
        if (aggregations == null) {
            System.out.println("No aggregations found");
            return searchResult;
        }
        /** 当前查询到的结果, 所有涉及到的品牌*/
        ParsedLongTerms brandIdAgg = aggregations.get("brandIdAgg");
        if (brandIdAgg == null) {
            System.out.println("No brand aggregation found");
        } else {
            // 解析品牌聚合
            List<? extends Terms.Bucket> buckets = brandIdAgg.getBuckets();
            List<SearchResult.BrandVo> brandVos = new ArrayList<>();
            for (Terms.Bucket bucket : buckets) {
                SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
                brandVo.setBrandId(Long.valueOf(bucket.getKeyAsString()));

                Terms brandNameAgg = bucket.getAggregations().get("brandNameAgg");
                String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();
                brandVo.setBrandName(brandName);

                brandVos.add(brandVo);
            }
            searchResult.setBrands(brandVos);
            /*** 当前查询到的结果, 所有涉及到的分类*/
            List<SearchResult.CatalogVo> catalogs = new ArrayList<>();
            ParsedLongTerms catalogIdAgg = aggregations.get("catalogIdAgg");

            List<? extends Terms.Bucket> catalogBuckets = catalogIdAgg.getBuckets();

            for (Terms.Bucket catalogBucket : catalogBuckets) {
                SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
                String catalogId = catalogBucket.getKeyAsString();
                catalogVo.setCatalogId(Long.valueOf(catalogId));
                Terms catalogNameAgg = catalogBucket.getAggregations().get("catalogNameAgg");
                String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();
                catalogVo.setCatalogName(catalogName);
                catalogs.add(catalogVo);
            }
            searchResult.setCatalogs(catalogs);
            /** * 当前查询的结果 所有涉及到所有属性*/
            List<SearchResult.AttrVo> attrs = new ArrayList<>();
            ParsedNested attrsAgg = aggregations.get("attrsAgg");
            Terms attrIdAgg = attrsAgg.getAggregations().get("attrIdAgg");

            for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {
                SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
                //attrId
                String attrId = bucket.getKeyAsString();
                attrVo.setAttrId(Long.valueOf(attrId));

                Aggregations attrIdBucketAggregations = bucket.getAggregations();
                //attrName
                Terms attrNameAgg = attrIdBucketAggregations.get("attrNameAgg");
                String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();
                attrVo.setAttrName(attrName);
                //attrValues  []
                Terms attrValueAgg = attrIdBucketAggregations.get("attrValueAgg");
                List<String> values = new ArrayList<>();
                for (Terms.Bucket attrValueAggBucket : attrValueAgg.getBuckets()) {
                    values.add(attrValueAggBucket.getKeyAsString());
                }
                attrVo.setAttrValue(values);

                attrs.add(attrVo);

            }
            searchResult.setAttrs(attrs);
        }
        return searchResult;
    }

    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
/**
 * =============================================
 * query  begin
 */
        //1.1 keyword
        if(StringUtils.isNotEmpty(searchParam.getKeyword()))
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",searchParam.getKeyword()));
        //1.2 catalog

        if(searchParam.getCatalog3Id()!=null)
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchParam.getCatalog3Id()));
        //1.3 brandId

        if(searchParam.getBrandId()!=null && searchParam.getBrandId().size()>0){
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchParam.getBrandId()));
        }
        //1.4 skuprice  10_20000
        //  10_    _20000   10_20000
        if (StringUtils.isNotBlank(searchParam.getSkuPrice())){
            RangeQueryBuilder skuPrice = QueryBuilders.rangeQuery("skuPrice");

            String[] prices = searchParam.getSkuPrice().split("_");
            if(prices.length==2){
                skuPrice.lte(prices[1]);
                skuPrice.gte(prices[0]);
            }else if(searchParam.getSkuPrice().startsWith("_")){
                skuPrice.lte(prices[1]);
            }else if(searchParam.getSkuPrice().endsWith("_")){
                skuPrice.gte(prices[0]);
            }
            boolQueryBuilder.filter(skuPrice);
        }

        //1.5  nested  attrs   1_3:3&2_4:8

        if(searchParam.getAttrs()!=null && searchParam.getAttrs().size()>0){

            for (String attrStr : searchParam.getAttrs()) {

                String[] s = attrStr.split("_");
                String attrId = s[0];

                String[] sttrValues = s[1].split(":");

                BoolQueryBuilder boolNestedQueryBuilder = QueryBuilders.boolQuery();
                boolNestedQueryBuilder.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                boolNestedQueryBuilder.must(QueryBuilders.termQuery("attrs.attrValue",sttrValues[1]));

                NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", boolNestedQueryBuilder, ScoreMode.None);
                boolQueryBuilder.filter(attrs);
            }


        }
        sourceBuilder.query(boolQueryBuilder);

/**
 * =============================================
 * query  end
 */


        //1.4 sort  saleCount_desc

        if(StringUtils.isNotBlank(searchParam.getSort())){
            String[] strings = searchParam.getSort().split("_");

            sourceBuilder.sort(strings[0],"asc".equalsIgnoreCase(strings[1])? SortOrder.ASC:SortOrder.DESC);
        }

        //1.6 分页
        sourceBuilder.from(0);
        sourceBuilder.size(20);

        //1.7 高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("skuTitle");
        highlightBuilder.preTags("<span style='color:skyblue;font-size:18px'>");
        highlightBuilder.postTags("</span>");

        sourceBuilder.highlighter(highlightBuilder);

        //1.8  aggs
        TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandIdAgg").field("brandId");
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName");
        brandIdAgg.subAggregation(brandNameAgg);

        TermsAggregationBuilder catalogIdAgg = AggregationBuilders.terms("catalogIdAgg").field("catalogId");
        TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName");
        catalogIdAgg.subAggregation(catalogNameAgg);


        NestedAggregationBuilder nested = AggregationBuilders.nested("attrsAgg", "attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId");
        TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg").field("attrs.attrName");
        TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue");

        nested.subAggregation(attrIdAgg);
        attrIdAgg.subAggregation(attrNameAgg);
        attrIdAgg.subAggregation(attrValueAgg);

        sourceBuilder.aggregation(brandIdAgg);
        sourceBuilder.aggregation(catalogIdAgg);
        sourceBuilder.aggregation(nested);



        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("product");
        searchRequest.source(sourceBuilder);
        return searchRequest;
    }

}
